package com.lin.generate.common.utill;

import java.util.Iterator;
import java.util.Objects;

/**
 * 字符串拼接工具类，每个线程共享一个StringBuilder，将少字符串 + 时的性能损耗，以及对最终字符长度估计不足造成数组成倍扩充造成的内存浪费。
 * 如果同一个线程中嵌套使用的，后面直接new 一个
 * @Author: lin.zhao@pinlandata.com
 * @Date: 2021/10/1 22:48
 */
public class StrBuilderUtil {
    private StringBuilder curSb = null;
    private boolean useThreadBuilder;
    private static final ThreadLocal<StringBuilder> THREAD_BUILDER
            = ThreadLocal.withInitial(() -> new StringBuilder(64));

    private static final ThreadLocal<Integer> BUILDER_STATUS = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return NOT_USE;
        }
    };

    public static final Integer NOT_USE = -1;
    public static final Integer USING = 1;

    private StrBuilderUtil() {
        setUseThreadBuilder(false);
        curSb = tryLock() ? THREAD_BUILDER.get() : new StringBuilder();
    }

    public static StrBuilderUtil me() {
        return new StrBuilderUtil();
    }

    public StrBuilderUtil append(Object str) {
        try {
            curSb.append(str);
        } catch (Exception e) {
            unlock();
            throw new RuntimeException(e);
        }
        return this;
    }

    @Override
    public synchronized String toString() {
        if (curSb == null) {
            return StrUtils.EMPTY_STR;
        }
        String str = curSb.toString();
        unlock();
        return str;
    }

    /**
     * 直接获取 制定位置之间的字符，位置 可为 负数
     */
    public String substring(int start, int end) {

        int length = curSb.length();
        if (length < 1) {
            unlock();
            return StrUtils.EMPTY_STR;
        }
        if (end < 0) {
            end = length + end;
        }
        if (start < 0) {
            start = length + start;
        }
        if (start > end) {
            unlock();
            return StrUtils.EMPTY_STR;
        }
        String substring = curSb.substring(start, end);
        unlock();
        return substring;
    }

    public static String concat(Object... args) {
        if (args == null || args.length == 0) {
            return StrUtils.EMPTY_STR;
        }
        StrBuilderUtil me = StrBuilderUtil.me();
        for (int i = 0; i < args.length; i++) {
            me.curSb.append(StrUtils.nvl(args[i]));
        }
        return me.toString();
    }

    public static String concat(String separator, Iterator iterator) {
        if (iterator == null || !iterator.hasNext()) {
            return StrUtils.EMPTY_STR;
        }
        StrBuilderUtil me = StrBuilderUtil.me();
        me.curSb.append(iterator.next());
        while (iterator.hasNext()) {
            me.curSb.append(separator).append(iterator.next());
        }

        return me.toString();
    }

    private boolean tryLock() {
        if (Objects.equals(BUILDER_STATUS.get(), NOT_USE)) {
            BUILDER_STATUS.set(USING);
            setUseThreadBuilder(true);
            return getUseThreadBuilder();
        }
        return false;
    }

    private void unlock() {
        if (useThreadBuilder) {
            BUILDER_STATUS.set(NOT_USE);
            curSb.setLength(0);
            setUseThreadBuilder(false);
        }
    }

    public int length() {
        return curSb.length();
    }

    public StrBuilderUtil delete(int start, int end) {
        curSb.delete(start, end);
        return this;
    }

    synchronized public void  setUseThreadBuilder(boolean used){
        this.useThreadBuilder=used;
    }
    synchronized public boolean getUseThreadBuilder(){
        return this.useThreadBuilder;
    }
}
